#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<pthread.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<regex.h>



#define LOCAL_LISTEN_PORT 28080

typedef struct mh   //38字节的命令头部信息，并且提供一个标志为表示该信息是否是正确的信息
{
	char vaild;  //标记此头部信息是否合法 ,0表示不是要转发，1为转发
	unsigned char dstIP[4];  //xxx.xxx.xxx.xxx //记录从命令行参数获取的要练杰的服务器的IP
	short int dstport;        //记录从命令行参数衷获取的服务器的监听的端口,服务端需要运行写好的服务端
	char token[32];
	int socket_remote;  //记录发来数据的socket
	int socket_srv;  //记录要服务端的socket
	char rawdata[38];  //用于存储接收到的38字节首部原始数据
} MarkHead;


MarkHead mh;  //用于标记每次新产生的客户端链接信息
typedef struct srvinfo
{
	unsigned char srv_ip[20];
	short int srv_port;

}SrvInfo;

void* SrvToClient_thread(void* para);  //通讯线程，服务端往客户端数据流线程。
void* ClientToSrv_thread(void* para);  //通讯线程，客户端往服务端数据流线程。
void* AcceptConections(void* para);   //用于监听本地地址新进来的链接，根据当前MarkHead信息决定是否要发送head头信息给服务器

int main(int argc,char** argv)

{
	//解析参数
	if(argc<=1)
	{
		printf("usage:a.exe  [serverIP]:[Port]\n");
		return 0;
	}
	char argbuf[64]={0};
	strncpy(argbuf,argv[1],strlen(argv[1]));
	printf("get arg:%s\n",argbuf);
	regex_t pattern;
	regmatch_t rp[2];
	size_t nmatch=2;
	int errno=0;
	char errbuff[128]={0};
	//char *regex="(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9]):\\d{1,5}";
	char *regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]).){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]):[0-9]{1,5}$";
	errno=regcomp(&pattern,regex,REG_ICASE|REG_EXTENDED);
	if(0!=errno)
	{
		regerror(errno,&pattern,errbuff,sizeof(errbuff));

		printf("regex comp fail:%s\n",errbuff);
		return 0;
	}
	printf("regcomp success..\n");
	errno=regexec(&pattern,argbuf,nmatch,rp,0);
	if(0!=errno)
	{
		regerror(errno,&pattern,errbuff,sizeof(errbuff));
		printf("regexec  vaild:%s-->%s\n",errbuff,argbuf);
		printf("usage:a.exe  [serverIP]:[Port]\n");
		return 0;
	}
	char srvIP[16]={0};
	unsigned short int Port=0;

	if(2!=sscanf(argbuf,"%s%hu",&srvIP,&Port))
	{
		printf("parse arg fail:argbuf=%s,srvIP=%s,Port=%d\n",argbuf,srvIP,Port);
		return 0;
	}
	if(Port<=0||Port>65535){printf("port vaild\n");return 0;}
	printf("parse :%s:%d\n",srvIP,Port);
	//开始本地监听
	//准备监听线程参数
	SrvInfo si;
	strcpy(si.srv_ip,srvIP);
	si.srv_port=Port;
	pthread_t tid;
	int err;
	err=pthread_create(&tid,NULL,AcceptConections,(void*)&si);


	//准备循环接收并解析输入的转发命令,将转发信息做成头38字节数据写入全局MarkHead变量
	char command[8]={0};
	char arg[32]={0};
	while(1)
	{
		memset(command,0,8);
		memset(arg,0,32);
		printf("#");
		scanf("%s%s",&command,&arg);
		memset(mh.dstIP,0,20);
		mh.dstport=0;
		memset(mh.rawdata,0,38);
		//解析命令与参数	,保存解析结果到全局变量mh中
		if(0==strcmp(command,"to"))
		{
			if(!regexec(&pattern,arg,0,NULL,0))
			{
				if(5!=sscanf(arg,"%u.%u.%u.%u:%u",&mh.dstIP[0],&mh.dstIP[1],&mh.dstIP[2],&mh.dstIP[3],&mh.dstport))
				{
					printf("only support command:to,exit,help\n");
					printf("ex. to 192.168.1.1:33");
					continue;
				}
				sprintf(mh.rawdata,"%c%c%c%c%hub60d84d4168a2bf7ced43dcf29e7b18e",mh.dstIP[0],mh.dstIP[1],mh.dstIP[2],mh.dstIP[3],mh.dstport);
				printf("parse args,srvIP=%u.%u.%u.%u,Port=%hu,token=%s\n",mh.dstIP[0],mh.dstIP[2],mh.dstIP[3],mh.dstport,mh.token);
			}
		}
		else if(0==strcmp(command,"exit"))
		{
			return 0;
		}
		else if(0==strcmp(command,"help"))
		{

			printf("only support command:to,exit,help\n");
			printf("ex. to 192.168.1.1:33");
			continue;
		}
		else
		{
			printf("only support command:to,exit,help\n");
			printf("ex. to 192.168.1.1:33");
			continue;
		}

	}


	regfree(&pattern);
	return 0;
}


void* SrvToClient_thread(void* para)
{
	MarkHead headinfo;
	memcpy(&headinfo,(MarkHead*)para,sizeof(MarkHead));
	//	printf(" Client-->srv thread,socket client=%d\t,socket srv=%d\n",client,srv);
	char BuffClientRcv[1024]= {0};
	char BuffSrvRcv[1024]= {0};
	int RcvBytes=0;
	int SendBytes=0;
	printf("begin to recv data from :%d\n",mh.socket_srv);
	while((RcvBytes=recv(headinfo.socket_srv,BuffClientRcv,1024,0))!=-1&&RcvBytes!=0)
	{
		printf("get data from srv:%d\n",RcvBytes);
		SendBytes=send(headinfo.socket_remote,BuffClientRcv,RcvBytes,0); //send to client
		memset(BuffClientRcv,0,1024);
	}

	printf("srv recv error,RcvBytes=%d\n",RcvBytes);
	close(headinfo.socket_remote);
	close(headinfo.socket_srv);
	return ;


}
void* ClientToSrv_thread(void* para)
{
	MarkHead headinfo;
	memcpy(&headinfo,(MarkHead*)para,sizeof(MarkHead));
	//	printf(" Client-->srv thread,socket client=%d\t,socket srv=%d\n",client,srv);
	char BuffClientRcv[1024]= {0};
	char BuffSrvRcv[1024]= {0};
	int RcvBytes=0;
	int SendBytes=0;
	//if(0==mh.vaild)
	//{
	//   send(mh.socket_srv,mh.rawdata,38,0);   //如果是默认转发，需要吧之前接收的首部38字节发送
	//		printf("send head data success!\n");
	//}

	printf("begin to recv data from :%d\n",headinfo.socket_remote);
	while((RcvBytes=recv(headinfo.socket_remote,BuffClientRcv,1024,0))!=-1&&RcvBytes!=0)
	{
		printf("get data from client:%d\n",RcvBytes);
		SendBytes=send(headinfo.socket_srv,BuffClientRcv,RcvBytes,0); //send to srv
		memset(BuffClientRcv,0,1024);
	}
	printf("client recv error,RcvBytes=%d\n",RcvBytes);
	close(headinfo.socket_remote);
	close(headinfo.socket_srv);
	return ;


}


void* AcceptConections(void* para)   //用于监听本地地址新进来的链接，根据当前MarkHead信息决定是否要发送head头信息给服务器
{

	SrvInfo si;
	memcpy(&si,(SrvInfo*)para,sizeof(SrvInfo));

	//1.create socket
	int s=socket(AF_INET,SOCK_STREAM,0);
	if(-1==s)
	{
		printf("create socket error\n");
		return 0;
	}
	//2.prepare a socet_addr
	struct sockaddr_in SrvAddr;
	SrvAddr.sin_family=AF_INET;
	SrvAddr.sin_port=htons(LOCAL_LISTEN_PORT);
	SrvAddr.sin_addr.s_addr=INADDR_ANY;
	//3.bind address
	int ret=bind(s,(struct sockaddr*)&SrvAddr,sizeof(struct sockaddr_in));
	if(-1==ret)
	{
		printf("bind socket error\n");
		return 0;
	}
	else
		printf("bind success on :%d\n",LOCAL_LISTEN_PORT);
	//4.begin listen
	ret=listen(s,10);
	if(-1==ret)
	{
		printf("listen socket error\n");
		return 0;
	}
	//	else printf("listen success::8005\n");
	//5.prepare a client socket
	struct sockaddr_in sacc;
	int len_sacc=sizeof(struct sockaddr_in);
	int client;
	//6.begin while to accept client
	pthread_t tid;
	int RecvTimeOut=120*1000;
	int SendTimeOut=120*1000;
	int err;

	while(1)
	{
		printf("begin accept...\n");
		client=accept(s,(struct sockaddr*)&sacc,&len_sacc);
		printf("accept one connectino\n");
		if(-1==client)
		{
			printf("accept socket error\n");
			return 0;
		}
		else
		{
			printf("begin a new session:%d\n",client);
			printf("checking mark_head data...\n");
			//开始处理新的连接。链接服务端，并发送38字节首部数据	

			mh.socket_remote=client;
			int sock_srv=socket(AF_INET,SOCK_STREAM,0);
			struct sockaddr_in addr_srv;
			addr_srv.sin_family=AF_INET;
			addr_srv.sin_port=htons(mh.dstport);
			addr_srv.sin_addr.s_addr=inet_addr(mh.dstIP);

			if(-1==connect(sock_srv,(struct sockaddr*)&addr_srv,sizeof(struct sockaddr)))
			{
				printf("connect to srv error\n");
				return 0;
			}

			mh.socket_srv=sock_srv;
			setsockopt(mh.socket_remote,SOL_SOCKET,SO_RCVTIMEO,(char*)&RecvTimeOut,sizeof(int));
			setsockopt(mh.socket_remote,SOL_SOCKET,SO_SNDTIMEO,(char*)&SendTimeOut,sizeof(int));
			setsockopt(mh.socket_srv,SOL_SOCKET,SO_RCVTIMEO,(char*)&RecvTimeOut,sizeof(int));
			setsockopt(mh.socket_srv,SOL_SOCKET,SO_SNDTIMEO,(char*)&SendTimeOut,sizeof(int));

			//开始转发流程，跟据mh_data.valid标志来确定是否要发送首部数据raw_data到srv端
			int ret=0;
			ret=send(sock_srv,mh.rawdata,38,0);  //发送38字节转发信息给服务端
			if(ret!=-1)
			{
				printf("send to srv rawdata success,send bytes:%d,content:%s\n",ret,mh.rawdata);
			}
			else 
			{
				printf("send error\n");
				close(mh.socket_srv);
				close(mh.socket_remote);
				continue;
			}

			err=pthread_create(&tid,NULL,ClientToSrv_thread,(void*)&mh);
			err=pthread_create(&tid,NULL,SrvToClient_thread,(void*)&mh);

		}

	}
	close(s);
}
